/*            Copyright(c) 2006-2008 Dave Sexton           *
 * http://www.codeplex.com/DocProject                      *
 * http://www.codeplex.com/DocProject/Project/License.aspx *
 ***********************************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using VSLangProj80;
using System.Threading;
using DaveSexton.DocProject.Resources;

namespace DaveSexton.DocProject.Engine
{
	public abstract class BuildStep<TEngine> : MarshalByRefObject, IBuildStep, IDisposable
		where TEngine : IBuildEngine
	{
		#region Public Properties
		public TEngine Engine
		{
			get
			{
				return engine;
			}
		}

		public bool ContinueOnError
		{
			get
			{
				return continueOnError;
			}
			set
			{
				continueOnError = value;
			}
		}

		/// <summary>
		/// Gets or sets whether the step is executed on a background thread to improve UI responsiveness.  
		/// However, with regards to other steps in the process, the step is still executed synchronously.
		/// </summary>
		public bool RunInBackground
		{
			get
			{
				return runInBackground;
			}
			set
			{
				runInBackground = value;
			}
		}

		public bool IncludeInPartialBuild
		{
			get
			{
				return includeInPartialBuild;
			}
			set
			{
				includeInPartialBuild = value;
			}
		}

		public BuildContext CurrentContext
		{
			get
			{
				return currentContext;
			}
		}

		public abstract string Name { get; }
		#endregion

		#region Private / Protected
		private bool continueOnError, runInBackground, includeInPartialBuild;
		private readonly TEngine engine;
		private BuildContext currentContext;
		private readonly object syncCancelBuild = new object();
		#endregion

		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="BuildStep" /> class for derived classes.
		/// </summary>
		protected BuildStep(TEngine engine)
		{
			if (engine == null)
				throw new ArgumentNullException("engine");

			this.engine = engine;
		}
		#endregion

		#region Methods
		[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.LinkDemand,
			Flags = System.Security.Permissions.SecurityPermissionFlag.Infrastructure)]
		public override object InitializeLifetimeService()
		{
			return null;
		}

		public void Execute(BuildContext context)
		{
			if (context == null)
				throw new ArgumentNullException("context");

			currentContext = context;

			ExecuteInternal(context);

			lock (syncCancelBuild)
			{
				currentContext = null;
			}
		}

		public void Cancel()
		{
			if (!runInBackground)
				throw new InvalidOperationException(Errors.CancelSynchronousStep);

			lock (syncCancelBuild)
			{
				if (currentContext != null)
					CancelInternal(currentContext);
			}
		}

		protected abstract void ExecuteInternal(BuildContext context);

		protected abstract void CancelInternal(BuildContext context);

		public override string ToString()
		{
			return Name + " Build Step";
		}
		#endregion

		#region IBuildStep Members
		IBuildEngine IBuildStep.Engine
		{
			get
			{
				return Engine;
			}
		}
		#endregion

		#region IDisposable Members
		/// <summary>
		/// Releases all resources used by an instance of the <see cref="BuildStep" /> class.
		/// </summary>
		/// <remarks>
		/// This method calls the virtual <see cref="Dispose(bool)" /> method, passing in <strong>true</strong>, and then suppresses 
		/// finalization of the instance.
		/// </remarks>
		public void Dispose()
		{
			Dispose(true);
			GC.SuppressFinalize(this);
		}

		/// <summary>
		/// Releases unmanaged resources before an instance of the <see cref="BuildStep" /> class is reclaimed by garbage collection.
		/// </summary>
		/// <remarks>
		/// This method releases unmanaged resources by calling the virtual <see cref="Dispose(bool)" /> method, passing in <strong>false</strong>.
		/// </remarks>
		~BuildStep()
		{
			Dispose(false);
		}

		/// <summary>
		/// Releases the unmanaged resources used by an instance of the <see cref="BuildStep" /> class and optionally releases the managed resources.
		/// </summary>
		/// <param name="disposing"><strong>true</strong> to release both managed and unmanaged resources; <strong>false</strong> to release only unmanaged resources.</param>
		protected virtual void Dispose(bool disposing)
		{
		}
		#endregion
	}
}
